﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Text.RegularExpressions;
using Prism.WebBuilder.Lib.Cui;

namespace Prism.WebBuilder.Script
{
	public class PwbScript
	{
		private string _path;
		private bool _compiled;
		private Assembly _compiledAssembly;
		private List<string> _targets;

		public PwbScript SetTarget(string target)
		{
			_targets.Add(target);
			return this;
		}

		public PwbScript(string path)
		{
			_path = Path.GetFullPath(path);
			_targets = new List<string>();
		}

		public void Execute()
		{
			if (!_compiled)
				Compile();
			
			if (_compiled)
			{
				Cui.Info("Executing {0} ...", Path.GetFileName(_path));
				using (Cui.BeginIndent())
				{
					object o = _compiledAssembly.CreateInstance("PwbScript");
					o.GetType().GetMethod("Execute").Invoke(o, null);
				}
			}
		}

		private void Compile()
		{
			Cui.Info("Compiling {0} ...", Path.GetFileName( _path));
			using (var codeProvider = Microsoft.CSharp.CSharpCodeProvider.CreateProvider("CS"))
			{
				var p = new System.CodeDom.Compiler.CompilerParameters();
				p.GenerateInMemory = true;
				p.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
				var results = codeProvider.CompileAssemblyFromSource(p, ProcessSource(File.ReadAllText(_path)));

				foreach (System.CodeDom.Compiler.CompilerError error in results.Errors)
				{					
					Console.WriteLine(string.Format("error({0}):{1}", error.Line, error.ErrorText));
				}
				if (!results.Errors.HasErrors)
				{
					_compiled = true;
					_compiledAssembly = results.CompiledAssembly;
				}
			}			
		}
		private string TargetsExecuteSource()
		{
			StringBuilder builder = new StringBuilder();
			foreach(var target in _targets)
			{
				builder.AppendFormat("ScriptFactory.Create<Execute>().Init(\"{0}\");", target);
			}
			return builder.ToString();
		}
		private string ProcessSource(string source)
		{
			string resBegin = @"using Prism.WebBuilder.Processors;
static class ScriptFactory	
{
	public static T Create<T>()
		where T: Prism.WebBuilder.Processors.Base.ProcessorBase, new()
	{
		T proc = new T();
		proc.Args.RootPath = System.IO.Path.GetDirectoryName(@" + "\"" + _path + "\"" +@");
		return proc;
	}
}
class PwbScript {
	public void Execute() {".Replace("\r\n", " ");
			string resEnd = ";"+TargetsExecuteSource()+"}}";
			string res = "new " +source;

			Regex regex = new Regex(@"\)\s*(?<letter>\w)");
			res = regex.Replace(res, "); new $1");
			
			Regex regex3 = new Regex(@"\(\s*(?<letter>\w)");
			res = regex3.Replace(res, "( new $1");
			
			Regex regex4 = new Regex(@"\,\s*(?<letter>\w)");
			res = regex4.Replace(res, ", new $1");
			
			Regex regex2 = new Regex(@"new\s+(?<letter>\w+)\s*\(");
			res = regex2.Replace(res, "ScriptFactory.Create<$1>().Init(");

			return resBegin + res + resEnd;

		}

	}
}
